#!/usr/bin/python
'''
dlm2dot.py:
	Take an input graph file and convert to a dot file.  This script
	interprets the cluster label and generates an appropriate dot
	graph.  

	Input format is edge-list with some delimiter used between
	vertice labels (and optionally a weight).  For now any weight 
	values are ignored if present.  If a vertex belongs to a cluster that
	cluster name is a prefix on the vertex name.  By default the delimiter
	between vertex labels is space and a "/" between cluster name and
	vertex name in the label.
	
usage:
	dlm2dot.py input_file > output_file
		all arguments are filenames

Created on May 1, 2011
@author: ncrowell
'''

import sys
import networkx as nx

def splitname(v):
	cluster_v = ""
	tmp = v.split('/')
	if ( len(tmp) > 1 ):
		v = tmp[1]
		cluster_v = tmp[0]
	return v, cluster_v

# For now, the entire graph ends up loaded in memory before writing
# out the dot file.  For larger graphs may need to switch to 
# a two-phase approach which uses file buffers to store each subgraph
# before generating the final output graph.

# produces a list of nx.MultiDiGraph objects where the first is
# the "top-level" graph in the dot output and the others are subgraphs. 
# Cannot just use the subgraph function for this since we would
# still need to the inter-subgraph edges which the "top-level" contains.
def createGraph(f):
	graph = nx.MultiDiGraph(name="G")
	subgraphs = dict()
	for line in f.readlines():
		if (line.strip().startswith('#')):
			continue
		s = line.split()
		if ( len(s) > 0 ):
			s = line.split()
			u, cluster_u = splitname(s[0])
			v, cluster_v = splitname(s[1])

			# generate new subgraph if necessary
			if ( not subgraphs.has_key(cluster_u)):
				subgraphs[cluster_u] = nx.MultiDiGraph(name=cluster_u)
			if ( not subgraphs.has_key(cluster_v)):
				subgraphs[cluster_v] = nx.MultiDiGraph(name=cluster_v)

			# add nodes to sets in subgraphs
			subgraphs[cluster_u].add_node(u)
			subgraphs[cluster_v].add_node(v)

			# inter cluster edge
			if ( cluster_u != cluster_v or cluster_u == ""):
				graph.add_edge(u,v)
			# intra cluster edge
			else :
				subgraphs[cluster_u].add_edge(u,v)

	ret = [graph]
	ret.extend( subgraphs.values() )
	return ret

def genDot(graphlist, f):
	"subgraph clusterA {"
	"1 -> 5"
	graph, subgraphs = graphlist[0], graphlist[1:]

	f.write("digraph "+ graph.name +"{ \n")
	for u,v in graph.edges():
		f.write(u + " -> " + v + "\n")

	for subgraph in subgraphs:
		f.write("subgraph cluster"+ subgraph.name +"{ \n")
		# node list
		for u in subgraph.nodes():
			f.write(u + "\n")

		# edge list
		for u,v in subgraph.edges():
			f.write(u + " -> " + v + "\n")
		f.write("}\n");
	f.write("}\n");


def main():
	if ( len(sys.argv) != 2 ): 
		print ("usage:\n" +
			"\tdlm2dot.py input_file > output_file\n" +
			"\t\tall arguments are filenames\n")
		sys.exit()	

	inputfile = file(sys.argv[1], 'r')
	outputfile = sys.stdout

	# process edge list
	graphlist = createGraph(inputfile)

	# genereate dot file from graph list
	genDot(graphlist, outputfile)


	inputfile.close()

if __name__ == '__main__':
	main()
